{# ----------------------------------------------------------------------------
 # SymForce - Copyright 2022, Skydio, Inc.
 # This source code is under the Apache 2.0 license found in the LICENSE file.
 # ---------------------------------------------------------------------------- #}


#pragma once

#include <cassert>
#include <cstdint>
#include <random>
#include <type_traits>

#include <sym/ops/storage_ops.h>
#include {{ lcm_type_t_include_dir }}

namespace sym {
namespace scalar {

/**
 * C++ StorageOps implementation for scalars.
 */
template <typename ScalarType>
struct StorageOps {
  using Scalar = ScalarType;
  static_assert(std::is_floating_point<ScalarType>::value, "");

  static constexpr int32_t StorageDim() {
    return 1;
  }

  static void ToStorage(const ScalarType& a, ScalarType* out) {
    assert(out != nullptr);
    out[0] = a;
  }

  static ScalarType FromStorage(const ScalarType* data) {
    assert(data != nullptr);
    return data[0];
  }

  static constexpr type_t TypeEnum() {
    return type_t::SCALAR;
  }

  template <typename Generator>
  static Scalar Random(Generator& gen) {
    return std::normal_distribution<Scalar>{}(gen);
  }
};

}  // namespace scalar

{% for scalar in scalar_types %}
template<>
struct StorageOps<{{ scalar }}> : public scalar::StorageOps<{{ scalar }}> {};
{% endfor %}

}  // namespace sym

// Explicit instantiation
{% for scalar in scalar_types %}
extern template struct sym::StorageOps<{{ scalar }}>;
{% endfor %}
